/***************************************************
 ** @Desc : This file for 共有方法
 ** @Time : 2019.04.01 11:48 
 ** @Author : Joker
 ** @File : global_method
 ** @Last Modified by : Joker
 ** @Last Modified time: 2019.04.01 11:48
 ** @Software: GoLand
****************************************************/
package utils

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"github.com/shopspring/decimal"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
	"io/ioutil"
	"math/rand"
	"net/url"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"time"
)

type GlobalMethod struct{}

//返回当前时间的字符串:2006-01-02 15:04:05
func (*GlobalMethod) GetNowTime() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

//返回当前时间的字符串:20060102150405
func (*GlobalMethod) GetNowTimeV2() string {
	return time.Now().Format("20060102150405")
}

//返回当前时间的字符串:2006-01-02
func (*GlobalMethod) GetNowTimeV3() string {
	return time.Now().Format("2006-01-02")
}

//在数字、大写字母、小写字母范围内生成num位的随机字符串
func (*GlobalMethod) RandomString(length int) string {
	// 48 ~ 57 数字
	// 65 ~ 90 A ~ Z
	// 97 ~ 122 a ~ z
	// 一共62个字符，在0~61进行随机，小于10时，在数字范围随机，
	// 小于36在大写范围内随机，其他在小写范围随机
	rand.Seed(time.Now().UnixNano())
	result := make([]string, 0, length)
	for i := 0; i < length; i++ {
		t := rand.Intn(62)
		if t < 10 {
			result = append(result, strconv.Itoa(rand.Intn(10)))
		} else if t < 36 {
			result = append(result, string(rand.Intn(26)+65))
		} else {
			result = append(result, string(rand.Intn(26)+97))
		}
	}
	return strings.Join(result, "")
}

//生成n位随机数字字符串
func (*GlobalMethod) RandomIntOfString(length int) string {
	result := make([]string, 0, length)
	rand.Seed(time.Now().UnixNano())
	for i := 0; i < length; i++ {
		randInt := rand.Intn(10)
		result = append(result, strconv.Itoa(randInt))
	}
	return strings.Join(result, "")
}

/* *
 * @Description: 注册密码加盐
 * @Author: Joker
 * @Date: 2019.04.01 11:48
 * @Param: pwd: 原始密码
 * @return: 返回hash和盐
 **/
func (this *GlobalMethod) PasswordSolt(pwd string) (string, string) {
	salt := this.RandomString(32)
	m5 := md5.New()
	m5.Write([]byte(pwd))
	m5.Write([]byte(salt))
	st := m5.Sum(nil)
	return hex.EncodeToString(st), salt
}

/* *
 * @Description: 登录密码加盐
 * @Author: Joker
 * @Date: 2019.04.01 11:49
 * @Param: pwd: 原始密码
 * @Param: salt: 盐值
 * @return: hash
 **/
func (*GlobalMethod) LoginPasswordSolt(pwd, salt string) string {
	m5 := md5.New()
	m5.Write([]byte(pwd))
	m5.Write([]byte(salt))
	st := m5.Sum(nil)
	return hex.EncodeToString(st)
}

/* *
 * @Description: 返回当前操作数据库的状态
 * @Author: Joker
 * @Date: 2019.04.01 14:37
 * @Param: code: 状态码,msg; 状态信息:url: 跳转地址; data: json内容
 * @return: 返回Json串
 **/
func (*GlobalMethod) JsonFormat(code int, data interface{}, msg string, url string) (json map[string]interface{}) {
	if code == 9 {
		json = map[string]interface{}{
			"code": code,
			"data": data,
			"msg":  msg,
			"url":  url,
		}
	} else {
		json = map[string]interface{}{
			"code": code,
			"msg":  msg,
			"url":  url,
		}
	}
	return json
}

// 返回当前操作数据库的状态:成功/失败
func (*GlobalMethod) GetDatabaseStatus(code int) map[string]interface{} {
	msg := FAILED_STRING
	if code == SUCCESS_FLAG {
		msg = SUCCESS_STRING
	}
	out := make(map[string]interface{})
	out["code"] = code
	out["msg"] = msg
	return out
}

// gbk转为utf-8
func (*GlobalMethod) GbkToUtf8(s []byte) ([]byte, error) {
	reader := transform.NewReader(bytes.NewReader(s), simplifiedchinese.GBK.NewDecoder())
	data, e := ioutil.ReadAll(reader)
	if e != nil {
		return nil, e
	}
	return data, nil
}

/* *
 * @Description: 金额分转化为元
 * @Author: Joker
 * @Date: 2019.04.10 9:20
 * @Param: fen: 分
 * @return: float64: 元; bool:false: 转化没有错误
 **/
func (*GlobalMethod) MoneyFenToYuan(fen string) (float64, bool) {
	f, _ := strconv.ParseFloat(fen, 64)
	fromFloat := decimal.NewFromFloat(f)
	return fromFloat.Div(decimal.New(1, 2)).Float64()
}

/* *
 * @Description: 金额元转化为分
 * @Author: Joker
 * @Date: 2019.04.10 9:19
 * @Param: yuan: 元
 * @return: string: 分; bool: true:转化没有错误
 **/
func (*GlobalMethod) MoneyYuanToFen(yuan float64) (string, bool) {
	fromFloat := decimal.NewFromFloat(yuan)
	f2, exact := fromFloat.Mul(decimal.New(1, 2)).Float64()
	return fmt.Sprintf("%.0f", f2), exact
}

func (*GlobalMethod) MoneyYuanToFloat(yuan string) (float64, error) {
	f, _ := strconv.ParseFloat(yuan, 64)
	f2 := fmt.Sprintf("%.2f", f)
	return strconv.ParseFloat(f2, 64)
}

func (*GlobalMethod) MoneyYuanToString(yuan float64) string {
	return fmt.Sprintf("%.2f", yuan)
}

//将map拼接成字符串,去掉最后一个&符号
func (*GlobalMethod) ToStringByMap(m map[string]string) (s string) {
	//键排序
	keys := make([]string, 0)
	for k := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	//连接键值对
	var buffer bytes.Buffer
	for i := 0; i < len(m); i++ {
		if m[keys[i]] == "" { //剔除值为空的参数
			continue
		}
		buffer.WriteString(keys[i])
		buffer.WriteString("=")
		buffer.WriteString(m[keys[i]])
		buffer.WriteString("&")
	}
	buf := buffer.String()
	return string([]byte(buf)[:len(buf)-1])
}

func (*GlobalMethod) UrlEncode(m map[string]string) string {
	//键排序
	keys := make([]string, 0)
	for k := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	v := url.Values{}
	for i := 0; i < len(m); i ++ {
		if m[keys[i]] == "" {
			continue
		}
		v.Add(keys[i], m[keys[i]])
	}
	return v.Encode()
}

// struct to map
func (*GlobalMethod) StructToMap(s interface{}) map[string]string {
	typeOf := reflect.TypeOf(s)
	valueOf := reflect.ValueOf(s)

	data := make(map[string]string)
	for i := 0; i < typeOf.NumField(); i++ {
		data[typeOf.Field(i).Name] = valueOf.Field(i).String()
	}
	return data
}

// 生成随机IP
func (*GlobalMethod) RandIpAddr() (ip string) {
	rand.Seed(time.Now().Unix())
	ip = fmt.Sprintf("%d.%d.%d.%d", rand.Intn(255), rand.Intn(255), rand.Intn(255), rand.Intn(255))
	return
}
